package com.hustcad.es.service;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.hustcad.es.entity.DocumentEntity;
import com.hustcad.es.msg.Result;
import com.hustcad.es.util.FileUtil;
import org.apache.commons.codec.binary.Base64;
import org.elasticsearch.action.admin.indices.create.CreateIndexRequest;
import org.elasticsearch.action.admin.indices.create.CreateIndexResponse;
import org.elasticsearch.action.admin.indices.get.GetIndexRequest;
import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.ingest.GetPipelineRequest;
import org.elasticsearch.action.ingest.GetPipelineResponse;
import org.elasticsearch.action.ingest.PutPipelineRequest;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.bytes.BytesArray;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.MatchQueryBuilder;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;

/**
 * Created by wangwen on 2019/9/27 16:50
 */
@Service
public class EsService {

    private RestHighLevelClient client;

    @Value("${esconfig.indexType}")
    private String indexType;

    @Value("${esconfig.pipeName}")
    private String pipeName;

    @Value("${esconfig.pathPrefix}")
    private String pathPrefix;

    @Autowired
    public EsService(RestHighLevelClient client) {
        this.client = client;
    }


    /**
     * 根据索引、关键字检索文档 返回文档名字、路径等
     * <p>1.根据索引,关键字检索</>
     * <p>2.将命中的全部结果返回</>
     *
     * @param indexName 索引
     * @param keyword   关键字
     * @return com.hustcad.es.msg.Result
     */
    public Result searchDocument(String indexName, String keyword) {
        Result result = new Result();
        List<DocumentEntity> documentList = new ArrayList<>();
        try {
            SearchRequest searchRequest = new SearchRequest();
            // 设置索引
            searchRequest.indices(indexName);
            // 设置类型
            searchRequest.types(indexType);
            SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
            // 检索关键字
            searchSourceBuilder.query(new MatchQueryBuilder("attachment.content", keyword));
            searchRequest.source(searchSourceBuilder);
            SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
            SearchHits searchHits = searchResponse.getHits();
            long totalHits = searchHits.totalHits;
            if (totalHits > 0) {
                searchHits.forEach(searchHit -> {
                    String sourceAsString = searchHit.getSourceAsString();
                    JSONObject jsonObject = JSON.parseObject(sourceAsString);
                    if (jsonObject.get("path") != null && jsonObject.get("name") != null) {
                        String path = jsonObject.get("path").toString();
                        String name = jsonObject.get("name").toString();
                        String oid = searchHit.getId();
                        DocumentEntity documentEntity = new DocumentEntity(indexName, path, name, oid);
                        documentList.add(documentEntity);
                    }
                });
                if (!documentList.isEmpty()) {
                    result.setData(documentList);
                    result.setCount(documentList.size());
                    result.setSuccess(true);
                }
            } else {
                result.setSuccess(false);
                result.setMsg("未检索到文档");
            }
        } catch (Exception e) {
            result.setError(e);
        }
        return result;
    }


    /**
     * 将文档写入(修改)ElasticSearch 并存入管道
     * <p>1.添加索引和管道</>
     * <p>2.根据path读取文档,用Base64解析文档内容，将解析后的字符串存入管道</>
     * <p>3.放入对应的索引下</>
     * <p>4.返回操作结果</>
     *
     * @param indexName 索引名
     * @param oid       文件id
     * @param name      文件名
     * @return com.hustcad.es.msg.Result
     */
    public Result uploadFile(String indexName, String oid, String name) {
        Result result = new Result();
        try {
            // 添加索引
            addIndex(indexName);
            String path = pathPrefix + name;
            File file = new File(path);
            if (file.exists()) {
                byte[] bytesByFile = FileUtil.getBytesByFile(path);
                // 转成base64编码字符串 交由Ingest-attachment解析
                String encode = Base64.encodeBase64String(bytesByFile);
                XContentBuilder builder = XContentFactory.cborBuilder();
                builder.startObject();
                builder.field("data", encode);
                builder.field("name", name);
                builder.field("path", path);
                builder.endObject();
                IndexRequest indexRequest = new IndexRequest(indexName, indexType, oid);
                indexRequest.setPipeline(pipeName);
                indexRequest.source(builder);
                // 将管道添加入索引
                client.index(indexRequest, RequestOptions.DEFAULT);
                result.setData(new DocumentEntity(indexName, path, name, oid));
                result.setSuccess(true);
            }
        } catch (Exception e) {
            result.setSuccess(false);
            result.setError(e);
        }
        return result;

    }


    /**
     * 删除文档
     *
     * @param indexName 索引
     * @param oid       文档id
     * @return com.hustcad.es.msg.Result
     */
    public Result deleteDocument(String indexName, String oid) {
        Result result = new Result();
        try {
            DeleteRequest request = new DeleteRequest();
            // 匹配索引
            request.index(indexName);
            // 匹配id
            request.id(oid);
            request.type(indexType);
            client.delete(request, RequestOptions.DEFAULT);
            result.setSuccess(true);
        } catch (IOException e) {
            result.setError(e);
            result.setSuccess(false);
        }
        return result;
    }

    // 判定索引是否存在
    private boolean existIndex(String indexName) throws Exception {
        GetIndexRequest request = new GetIndexRequest();
        request.indices(indexName);
        return client.indices().exists(request, RequestOptions.DEFAULT);
    }


    /**
     * 添加管道
     */
    private void addPipe() {
        try {
            if (!pipeExist()) {
                // 管道详情
                String source = "{\n" +
                        " \"description\" : \"Extract attachment information\",\n" +
                        " \"processors\":[\n" +
                        " {\n" +
                        "    \"attachment\":{\n" +
                        "        \"field\":\"data\",\n" +
                        "        \"indexed_chars\" : -1,\n" +
                        "        \"ignore_missing\":true\n" +
                        "     }\n" +
                        " },\n" +
                        " {\n" +
                        "     \"remove\":{\"field\":\"data\"}\n" +
                        " }]}";
                PutPipelineRequest request = new PutPipelineRequest(pipeName,
                        new BytesArray(source.getBytes(StandardCharsets.UTF_8)),
                        XContentType.JSON);
                request.timeout(TimeValue.timeValueMinutes(2));
                request.timeout("2m");
                // 添加管道
                client.ingest().putPipeline(request, RequestOptions.DEFAULT);

            }

        } catch (Exception e) {
            e.printStackTrace();
        }


    }

    /**
     * 查询管道是否存在
     *
     * @return boolean
     */
    private boolean pipeExist() throws Exception {
        GetPipelineRequest request = new GetPipelineRequest(pipeName);
        GetPipelineResponse response = client.ingest().getPipeline(request, RequestOptions.DEFAULT);
        return response.isFound();
    }

    /**
     * 添加索引 并添加管道
     *
     * @param indexName 索引
     * @return com.hustcad.es.msg.Result
     */
    public Result addIndex(String indexName) {
        Result result = new Result();
        try {
            if (!existIndex(indexName)) {
                CreateIndexRequest request = new CreateIndexRequest(indexName);
                CreateIndexResponse response = client.indices().create(request, RequestOptions.DEFAULT);
                result.setData(indexName);
                result.setSuccess(response.isAcknowledged());
                // 添加管道
                addPipe();
            }
        } catch (Exception e) {
            result.setError(e);
        }
        return result;
    }


}
